
package com.zy.je.common.core.utils.lang;

import com.zy.je.common.core.utils.collect.ListUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;

/**
 * 日期工具类, 继承org.apache.commons.lang.time.DateUtils类
 *
 * @author zy
 */
public class DateUtil extends org.apache.commons.lang3.time.DateUtils {
    /**
     * yyyy-MM-dd
     **/
    public static final String PATTERN_DEFAULT = "yyyy-MM-dd";
    /**
     * yyyy\\MM\\dd\\
     **/
    public static final String PATTERN_DAYPATH = "yyyy\\MM\\dd\\";
    /**
     * yyyy-MM-dd HH:mm:ss
     **/
    public static final String PATTERN_DATETIME = "yyyy-MM-dd HH:mm:ss";
    /**
     * yyyy-MM-dd HH:mm
     **/
    public static final String PATTERN_DATETIME_MINUTE = "yyyy-MM-dd HH:mm";
    /**
     * yyyyMMddHHmmss
     **/
    public static final String PATTERN_DATETIME_COMPACT = "yyyyMMddHHmmss";
    /**
     * yyyyMMdd
     **/
    public static final String PATTERN_DATE_COMPACT = "yyyyMMdd";
    /**
     * yyMMdd
     **/
    public static final String PATTERN_DATESHORT = "yyMMdd";
    /**
     * yyyyMM
     **/
    public static final String PATTERN_YEARMONTH = "yyyyMM";
    /**
     * utc
     */
    public static final String PATTERN_UTC = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

    // RFC 3339
    public static final String RFC_DATE = "yyyy-MM-dd'T'HH:mm:ssXXX";
    public static final String RFC_TZ = "yyyy-MM-dd'T'HH:mm:ss'Z'";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM/dd HH", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM.dd HH", "yyyy.MM",
            "yyyy年MM月dd日", "yyyy年MM月dd日 HH时mm分ss秒", "yyyy年MM月dd日 HH时mm分", "yyyy年MM月dd日 HH时", "yyyy年MM月",
            "yyyy", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"};

    /**
     * 得到日期字符串 ，转换格式（yyyy-MM-dd）
     */
    public static String formatDate(Date date) {
        return formatDate(date, "yyyy-MM-dd");
    }

    /**
     * 得到日期字符串 默认格式（yyyy-MM-dd） pattern可以为："yyyy-MM-dd" "HH:mm:ss" "E"
     */
    public static String formatDate(Date date, String pattern) {
        String formatDate = null;
        if (date != null) {
//			if (StringUtils.isNotBlank(pattern)) {
//				formatDate = DateFormatUtils.format(date, pattern);
//			} else {
//				formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
//			}
            if (StringUtils.isBlank(pattern)) {
                pattern = "yyyy-MM-dd";
            }
            formatDate = FastDateFormat.getInstance(pattern).format(date);
        }
        return formatDate;
    }


    /**
     * 得到当前时间字符串 格式（HH:mm:ss）
     */
    public static String getTime() {
        return formatDate(new Date(), "HH:mm:ss");
    }

    /**
     * 得到当前日期和时间字符串 格式（yyyy-MM-dd HH:mm:ss）
     */
    public static String getDateTime() {
        return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 得到当前年份字符串 格式（yyyy）
     */
    public static String getYear() {
        return formatDate(new Date(), "yyyy");
    }

    /**
     * 得到当前月份字符串 格式（MM）
     */
    public static String getMonth() {
        return formatDate(new Date(), "MM");
    }

    /**
     * 得到当天字符串 格式（dd）
     */
    public static String getDay() {
        return formatDate(new Date(), "dd");
    }

    /**
     * 得到当前星期字符串 格式（E）星期几
     */
    public static String getWeek() {
        return formatDate(new Date(), "E");
    }

    /**
     * 日期型字符串转化为日期 格式   see to DateUtils#parsePatterns
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }


    /**
     * <pre>
     * <h5>
     * 根据指定格式转换字符串为日期
     * </h5>
     * </pre>
     *
     * <pre>
     *               如果字符串格式不正确,则返回null
     * </pre>
     *
     * @param date    日期字符串
     * @param pattern 指定格式,参照类中常量定义
     * @return java.util.Date
     */
    public static Date parseDate(String date, String pattern) {
        try {
            return new SimpleDateFormat(pattern).parse(date);
        } catch (ParseException pe) {
            pe.getStackTrace();
            return null;
        }
    }

    /**
     * 获取日期小时字符串(yyyy-MM-dd HH:00:00)
     **/
    public static String getBeginOfDateHour(Date date) {
        return formatDate(date, DateUtil.PATTERN_DEFAULT) + " " + formatDate(date, "HH") + ":00:00";
    }

    /**
     * 获取日期小时字符串(yyyy-MM-dd HH:59:59)
     **/
    public static String getEndOfDateHour(Date date) {
        return formatDate(date, DateUtil.PATTERN_DEFAULT) + " " + formatDate(date, "HH") + ":59:59";
    }

    /**
     * 获取日期小时字符串(yyyy-MM-dd 00:00:00)
     **/
    public static String getBeginOfDay(Date date) {
        return formatDate(date, DateUtil.PATTERN_DEFAULT) + " 00:00:00";
    }

    /**
     * 获取日期小时字符串(yyyy-MM-dd 23:59:59)
     **/
    public static String getEndOfDay(Date date) {
        return formatDate(date, DateUtil.PATTERN_DEFAULT) + " 23:59:59";
    }


    /**
     * java8时间处理： java.util.Date <--> java.time.LocalDateTime  begin
     **/

    // 01. java.util.Date --> java.time.LocalDateTime
    public static LocalDateTime uDate2LocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    // 02. java.util.Date --> java.time.LocalDate
    public static LocalDate uDate2LocalDate(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalDate();
    }

    // 03. java.util.Date --> java.time.LocalTime
    public static LocalTime uDateToLocalTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        return localDateTime.toLocalTime();
    }


    // 04. java.time.LocalDateTime --> java.util.Date
    public static Date localDateTimeToUdate(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return Date.from(instant);
    }


    // 05. java.time.LocalDate --> java.util.Date
    public static Date localDateToUdate(LocalDate localDate) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

    // 06. java.time.LocalTime --> java.util.Date
    public static Date localTimeToUdate(LocalTime localTime) {
        LocalDate localDate = LocalDate.now();
        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return Date.from(instant);
    }

    /**
     * 计算两个时间相差多少个年
     *
     * @param start 开始时间
     * @param end 截止时间
     * @return
     */
    public static long yearsBetween(Date start, Date end) {
        LocalDateTime startLocalDate = uDate2LocalDateTime(start);
        LocalDateTime endLocalDate = uDate2LocalDateTime(end);
        return ChronoUnit.YEARS.between(startLocalDate, endLocalDate);
    }

    /**
     * 计算两个时间相差多少个月（开始时间 早与 截止时间，返回非负值，反之返回非正值）
     *
     * @param start 开始时间
     * @param end 截止时间
     * @return
     */
    public static long monthsBetween(Date start, Date end) {
        LocalDateTime startLocalDate = uDate2LocalDateTime(start);
        LocalDateTime endLocalDate = uDate2LocalDateTime(end);
        return ChronoUnit.MONTHS.between(startLocalDate, endLocalDate);
    }

    /**
     * 计算两个时间相差多少个天（开始时间 早与 截止时间，返回非负值，反之返回非正值）
     *
     * @param start 开始时间
     * @param end 截止时间
     * @return
     */
    public static long daysBetween(Date start, Date end) {
        LocalDateTime startLocalDate = uDate2LocalDateTime(start);
        LocalDateTime endLocalDate = uDate2LocalDateTime(end);
        return ChronoUnit.DAYS.between(startLocalDate, endLocalDate);
    }

    /**
     * 计算两个时间相差多少小时（开始时间 早与 截止时间，返回非负值，反之返回非正值）
     *
     * @param start 开始时间
     * @param end 截止时间
     * @return
     */
    public static long hoursBetween(Date start, Date end) {
        LocalDateTime startLocalDate = uDate2LocalDateTime(start);
        LocalDateTime endLocalDate = uDate2LocalDateTime(end);
        return ChronoUnit.HOURS.between(startLocalDate, endLocalDate);
    }

    /**
     * 计算两个时间相差多少分（开始时间 早与 截止时间，返回非负值，反之返回非正值）
     *
     * @param start 开始时间
     * @param end 截止时间
     * @return
     */
    public static long minutesBetween(Date start, Date end) {
        LocalDateTime startLocalDate = uDate2LocalDateTime(start);
        LocalDateTime endLocalDate = uDate2LocalDateTime(end);
        return ChronoUnit.MINUTES.between(startLocalDate, endLocalDate);
    }

    /**
     * 计算两个时间相差多少秒（开始时间 早与 截止时间，返回非负值，反之返回非正值）
     *
     * @param start 开始时间
     * @param end 截止时间
     * @return
     * @throws ParseException
     */
    public static long secondsBetween(Date start, Date end) {
        LocalDateTime startLocalDate = uDate2LocalDateTime(start);
        LocalDateTime endLocalDate = uDate2LocalDateTime(end);
        return ChronoUnit.SECONDS.between(startLocalDate, endLocalDate);
    }
    /** java8时间处理： java.util.Date <--> java.time.LocalDateTime  end**/


    public static List<Date> genDate(Date date, int dayRange) {
        List<Date> retList = ListUtil.newArrayList();
        if (dayRange > 0) {
            retList.add(date);
            for (int i = 1; i < dayRange; i++) {
                retList.add(DateUtil.addDays(date, i));
            }
        } else {
            for (int i = dayRange+1; i < 0; i++) {
                retList.add(DateUtil.addDays(date, i));
            }
            retList.add(date);
        }
        return retList;
    }

    public static List<Date> genDate(Date beginDate, Date endDate) {
        Long l = daysBetween(beginDate, endDate);
        int i = l.intValue();
        return genDate(beginDate,i);
    }

    public static Integer estimateAge(Date birthday, Date currentDate) {
        // 将java.util.Date转换为java.time.LocalDate
        LocalDate localBirthDate = birthday.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate targetDate = LocalDate.now();
        if (null != currentDate) {
            targetDate = currentDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        }
        // 计算年龄
        Period period = Period.between(localBirthDate, targetDate);
        return period.getYears();
    }

    /**
     * 预估生日
     * @param age
     * @return
     */
    public static Date estimateBirthday(Integer age){
        if(null==age){
            return null;
        }
        LocalDate currentDate = LocalDate.now();
        // 从当前日期减去年龄得到大约的出生日期
        LocalDate approximateBirthDate = currentDate.minusYears(age);
        Instant instant = approximateBirthDate.atStartOfDay(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }


}
